package com.zzyl.nursing.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.UserThreadLocal;
import com.zzyl.framework.web.service.TokenService;
import com.zzyl.nursing.domain.*;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.dto.UserLoginDto;
import com.zzyl.nursing.dto.member.BindingElderDto;
import com.zzyl.nursing.dto.member.DeviceDataListByDayWeekDto;
import com.zzyl.nursing.mapper.DeviceDataMapper;
import com.zzyl.nursing.mapper.FamilyMemberElderMapper;
import com.zzyl.nursing.mapper.FamilyMemberMapper;
import com.zzyl.nursing.service.*;
import com.zzyl.nursing.vo.FamilyMemberElderDetailVo;
import com.zzyl.nursing.vo.FamilyMemberElderVo;
import com.zzyl.nursing.vo.LoginVo;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 老人家属Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-10-22
 */
@Service
public class FamilyMemberServiceImpl extends ServiceImpl<FamilyMemberMapper, FamilyMember> implements IFamilyMemberService
{
    @Autowired
    private FamilyMemberMapper familyMemberMapper;
    @Autowired
    private IElderService elderService;
    @Autowired
    private FamilyMemberElderMapper familyMemberElderMapper;
    @Autowired
    private IFamilyMemberElderService familyMemberElderService;
    @Autowired
    private IDeviceService deviceService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private DeviceDataMapper deviceDataMapper;
    /**
     * 查询老人家属
     * 
     * @param id 老人家属主键
     * @return 老人家属
     */
    @Override
    public FamilyMember selectFamilyMemberById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询老人家属列表
     * 
     * @param familyMember 老人家属
     * @return 老人家属
     */
    @Override
    public List<FamilyMember> selectFamilyMemberList(FamilyMember familyMember)
    {
        return familyMemberMapper.selectFamilyMemberList(familyMember);
    }

    /**
     * 新增老人家属
     * 
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int insertFamilyMember(FamilyMember familyMember)
    {
        return save(familyMember) ? 1 : 0;
    }

    /**
     * 修改老人家属
     * 
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int updateFamilyMember(FamilyMember familyMember)
    {
        return updateById(familyMember) ? 1 : 0;
    }

    /**
     * 批量删除老人家属
     * 
     * @param ids 需要删除的老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除老人家属信息
     * 
     * @param id 老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberById(Long id)
    {
        return removeById(id) ? 1 : 0;
    }

    @Autowired
    private WechatService wechatService;

    private List<String> nickNameList = Arrays.asList("好柿开花", "大吉大利", "今晚吃鸡", "三羊开泰");

    @Autowired
    private TokenService tokenService;

    /**
     * 微信小程序登录接口
     *
     * @param dto
     * @return
     */
    @Override
    public LoginVo login(UserLoginDto dto) {
        //1. 获取微信唯一身份标识openId
        String openId = wechatService.getOpenId(dto.getCode());

        //2. 根据openId查询用户
        FamilyMember member = this.lambdaQuery().eq(FamilyMember::getOpenId, openId).one();

        //3. 如果用户不存在则新增用户（自动注册）
        if(member==null) {
            Collections.shuffle(nickNameList);//打乱集合中元素的顺序

            //生成随机昵称
            String nickName  = nickNameList.get(0) + RandomStringUtils.randomNumeric(4);

            member = FamilyMember.builder()
                    .openId(openId) //唯一标识
                    .name(nickName)//昵称
                    .build();
            this.save(member);
        }

        //4. 如果手机号不存在则获取微信绑定的手机号
        if(StrUtil.isBlank(member.getPhone())) {
            String phoneNum = wechatService.getPhoneNum(dto.getPhoneCode());

            //5. 更新手机号到用户表
//            FamilyMember memberUpdate = FamilyMember.builder()
//                    .id(member.getId()) //更新条件
//                    .phone(phoneNum)//更新字段对应的值
//                    .build();
//            this.updateById(memberUpdate);

            if(StrUtil.isNotBlank(phoneNum)) {
                this.lambdaUpdate()
                        .eq(FamilyMember::getId, member.getId()) //更新条件
                        .set(FamilyMember::getPhone, phoneNum)//更新字段对应的值
                        .update();
            }
        }

        //6. 基于userId和昵称生成Token令牌
        String token = tokenService.createToken(
                Map.of(
                        "userId", member.getId(),
                        "nickName", member.getName()
        ));

        //7. 封装响应结果对象
        return LoginVo.builder().nickName(member.getName()).token(token).build();
    }


    /**
     * 绑定老人
     *
     * @param dto
     */
    @Override
    public void bindingElder(BindingElderDto dto) {
        //1.获取家属的id
        Long userId = UserThreadLocal.getUserId();
        //2.判断老人是否存在
        Elder elder = elderService.lambdaQuery().eq(Elder::getIdCardNo, dto.getIdCard())
                .eq(Elder::getName, dto.getName())
                .one();
        if(elder == null){throw new BaseException("老人姓名或身份证号码错误，请检查是否正确");}
        //2.1 判断老人的入住状态（只有入住才可以绑定）
        if(elder.getStatus()!= 1){throw new BaseException("老人现不是入住状态下，无法绑定");}
        //3.已经绑定过的无需再绑定
        Long bindingCount = familyMemberElderService.lambdaQuery()
                .eq(FamilyMemberElder::getElderId, elder.getId())
                .eq(FamilyMemberElder::getFamilyMemberId, userId)
                .count();
        if(bindingCount > 0){throw new BaseException("您已与老人绑定，无需重新绑定");}
        //4.获取老人的id
        Long elderId = elder.getId();
        //5.封装数据，插入家属老人关联表
        FamilyMemberElder familyMemberElder = FamilyMemberElder
                .builder().
                familyMemberId(userId)
                .elderId(elderId)
                .remark(dto.getRemark())
                .build();
        familyMemberElderMapper.insert(familyMemberElder);
    }


    /**
     * 查询家人列表
     *
     * @return
     */
    @Override
    public List<FamilyMemberElderVo> selectBindingElder() {
        //1.获取老人家属id
        Long userId = UserThreadLocal.getUserId();
        if(userId == null){
            throw new BaseException("老人家属id获取失败");
        }
        //2.通过老人家属id，联查老人家属关联表和老人表
        List<FamilyMemberElderVo> bindingElderVoList = familyMemberElderService.selectBindingElder(userId);
        if(CollUtil.isEmpty(bindingElderVoList)){
            return Collections.emptyList();
//            throw new BaseException("查询无数据，无绑定老人");
        }
        //3.封装数据，返回数据
        return bindingElderVoList;
    }

    /**
     * 查看老人列表（分页查询）
     *
     * @param
     * @return
     */
    @Override
    public List<FamilyMemberElderDetailVo> selectBindingElderDetailList() {
        //1.获取家属id
        Long userId = UserThreadLocal.getUserId();
        //2.多表查询，封装数据
        List<FamilyMemberElderDetailVo> bindingElderDetailVoList = familyMemberElderMapper.selectBindingElderDetailList(userId);
        if(CollUtil.isEmpty(bindingElderDetailVoList)){
            return Collections.emptyList();
//            throw new BaseException("家人列表为空");
        }
        return bindingElderDetailVoList;
    }


    /**
     * 查询健康数据
     *
     * @param dto
     * @return
     */
    @Override
    public Map<String, Object> queryDevicePropertyStatus(DeviceDto dto) {
        //1.先判断设备是否存在
        Device device = deviceService.lambdaQuery().eq(Device::getDeviceName, dto.getDeviceName())
                .eq(Device::getProductKey, dto.getProductKey())
                .one();
        if(device == null){throw new BaseException("该老人没有绑定设备，无健康数据");}
        //2.从redis中取出最新数据
        //2.1 获取设备iotid
        String iotId = device.getIotId();
        //2.2 从redis获取最新数据,封装数据
        List<Map<String,Object>> propertyStatusList = new ArrayList<>();
        String devicePropertyStatus = (String)redisTemplate.opsForHash().get(CacheConstants.IOT_DEVICE_DATA_LATEST, iotId);
        //如果redis查询的最新健康数据为空，就返回空
        if(StrUtil.isBlank(devicePropertyStatus)){return Collections.emptyMap();}
        List<DeviceData> deviceDataList = JSONUtil.toList(devicePropertyStatus, DeviceData.class);
        //2.3 将心率放到索引3位置
        List<DeviceData> newDeviceDataList = new ArrayList<>(Arrays.asList(null,null,null,null));
        deviceDataList.forEach(deviceData -> {
            if("HeartRate".equals(deviceData.getFunctionId())){
                newDeviceDataList.set(3, deviceData);
            } else {
                for(int i = 0;i < 4; i++){
                    if(newDeviceDataList.get(i) == null){
                        newDeviceDataList.set(i,deviceData);
                        break;
                    }
                }
            }
        });
        //3. 封装数据
        newDeviceDataList.forEach(deviceData->{
            Map<String,Object> propertyMap = new HashMap<>();
            propertyMap.put("identifier", deviceData.getFunctionId());
            propertyMap.put("value", deviceData.getDataValue());
            LocalDateTime alarmTime = deviceData.getAlarmTime();
            long epochMilli = alarmTime.atZone(ZoneId.of("Asia/Shanghai")).toInstant().toEpochMilli();
            propertyMap.put("time",epochMilli);
            propertyStatusList.add(propertyMap);
        });
        Map<String,Object> propertyStatusInfoMap = new HashMap<>();
        propertyStatusInfoMap.put("propertyStatusInfo", propertyStatusList);
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("list", propertyStatusInfoMap);
        //4.返回数据
        return resultMap;
    }


    /**
     * 按天统计查询指标数据
     *
     * @return
     */
    @Override
    public List<Map<String, Object>> queryDeviceDataListByDay(DeviceDataListByDayWeekDto dto) {
        //1.将时间毫秒值转为LocalDateTime
        dto = changeTime(dto);
        //2.获取符合时间，功能，设备的数据
        List<Map<String, Object>> deviceDataList = deviceDataMapper.queryDeviceDataListByDay(dto);
        //如果24小时的数据为空（null），返回空集合
        /*if(CollUtil.isEmpty(deviceDataList)){return Collections.emptyList();}*/
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:00");
        //3.判断数据是否完整
        if(deviceDataList.size() != 24){
            //4.补全全天数据
            //4.1 准备一个新的数据集合(全天24小时)
            List<Map<String,Object>> newDeviceDataList = new ArrayList<>();
            //4.2 将新的数据集合都给填充数据，数据值都为0，时间正常排序
            for(int i = 0;i < 24;i++){
                LocalTime localTime = LocalTime.of(i, 0);
                String hour = localTime.format(timeFormatter);
                Map<String,Object> map = new HashMap<>();
                map.put("dateTime", hour);
                map.put("dataValue", 0);
                newDeviceDataList.add(map);
            }
            //4.3 遍历获取到的数据集合，将每个集合以时间为索引，根据索引添加到新数据集合中
            for (Map<String, Object> map : deviceDataList) {
                String dateTime = (String) map.get("dateTime");
                String[] split = dateTime.split(":");
                int index = Integer.parseInt(split[0]);
                newDeviceDataList.set(index,map);
            }
            //5. 返回数据集合
            return newDeviceDataList;
        }
        return deviceDataList;
    }

    /**
     * 将时间毫秒值（时间戳）转化为localDatetime
     * @param dto
     * @return
     */
    private static DeviceDataListByDayWeekDto changeTime(DeviceDataListByDayWeekDto dto) {
        Long startTime = dto.getStartTime();
        Long endTime = dto.getEndTime();
        dto.setEndLocalDateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(endTime), ZoneId.of("Asia/Shanghai")));
        dto.setStartLocalDateTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(startTime), ZoneId.of("Asia/Shanghai")));
        return dto;
    }


    /**
     * 按周统计查询指标数据
     *
     * @param dto
     * @return
     */
    @Override
    public List<Map<String, Object>> queryDeviceDataListByWeek(DeviceDataListByDayWeekDto dto) {
        //1.将时间毫秒值转为localDateTime
        dto = changeTime(dto);
        //2.再转成localdate
        LocalDate startDate = dto.getStartLocalDateTime().toLocalDate();
        LocalDate endDate = dto.getEndLocalDateTime().toLocalDate();
        //3.获取指定周，指定功能，指定设备的上报数据
        List<Map<String,Object>> deviceDataList = deviceDataMapper.queryDeviceDataListByWeek(dto);

        //如果一周七天的数据为空(null),返回为空集合
       /* if(CollUtil.isEmpty(deviceDataList)){
            return Collections.emptyList();
        }*/

        //判断数据是否完整
        if(deviceDataList.size() != 7){
            //4.补全数据
            Map<String,Object> deviceDataMap = new HashMap<>();
            deviceDataList.forEach(dataMap->deviceDataMap.put(dataMap.get("dateTime").toString(), dataMap.get("dataValue")));
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM.dd");
            //4.1 准备一个新的数据集合
            List<Map<String,Object>> completeDeviceDataList = new ArrayList<>();
            while(!startDate.isAfter(endDate)){
                String dateTime = startDate.format(formatter);
                //存在的话就不变，不存在就将dataValue变为0
                Object dataValue = deviceDataMap.getOrDefault(dateTime, 0);
                Map<String,Object> map = new HashMap<>();
                map.put("dateTime", dateTime);
                map.put("dataValue", dataValue);
                completeDeviceDataList.add(map);
                startDate = startDate.plusDays(1);
            }
            return completeDeviceDataList;
        }
        return deviceDataList;
    }


    /**
     * 解绑老人
     *
     * @param id
     */
    @Override
    public void deleteElderById(Long id) {
        familyMemberElderService.removeById(id);
    }
}
